
package com.idealighter.game.games.sirenniuniu.manager;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.core.constant.room.RoomActiveConstant;
import com.idealighter.game.dictionary.dic.SirenniuniuRoomTypeDic;
import com.idealighter.game.dictionary.domain.SirenniuniuRoomDomain;
import com.idealighter.game.gamehall.dto.MemInfo;
import com.idealighter.game.games.common.AbstractRoom;
import com.idealighter.game.games.common.AbstractSeat;
import com.idealighter.game.games.common.AbstractTable;
import com.idealighter.game.games.common.RoomState;
import com.idealighter.game.games.common.niuniu.NiuNiuCard;
import com.idealighter.game.games.sirenniuniu.dto.BillInfo;
import com.idealighter.game.games.sirenniuniu.dto.GameInfo;
import com.idealighter.game.games.sirenniuniu.dto.GameInfo.BetItem;
import com.idealighter.game.games.sirenniuniu.dto.GameInfo.CallDealerItem;
import com.idealighter.game.games.sirenniuniu.dto.GameInfo.MySelfCard;
import com.idealighter.game.games.sirenniuniu.dto.GameInfo.ReadyItem;
import com.idealighter.game.games.sirenniuniu.dto.GameInfo.ShowCardItem;
import com.idealighter.game.games.sirenniuniu.dto.RoomInfo;
import com.idealighter.game.games.sirenniuniu.dto.RoomTypeDetailInfo;
import com.idealighter.game.games.sirenniuniu.message.ResBetMsg;
import com.idealighter.game.games.sirenniuniu.message.ResCallDealerMsg;
import com.idealighter.game.games.sirenniuniu.message.ResCallDealerOverMsg;
import com.idealighter.game.games.sirenniuniu.message.ResChipsChangeMsg;
import com.idealighter.game.games.sirenniuniu.message.ResDealCardsMsg;
import com.idealighter.game.games.sirenniuniu.message.ResEnterGameHallMsg;
import com.idealighter.game.games.sirenniuniu.message.ResEnterRoomMsg;
import com.idealighter.game.games.sirenniuniu.message.ResEnterTableMsg;
import com.idealighter.game.games.sirenniuniu.message.ResExitRoomMsg;
import com.idealighter.game.games.sirenniuniu.message.ResExitTableMsg;
import com.idealighter.game.games.sirenniuniu.message.ResGameInfoMsg;
import com.idealighter.game.games.sirenniuniu.message.ResGameOverMsg;
import com.idealighter.game.games.sirenniuniu.message.ResOtherEnterTableMsg;
import com.idealighter.game.games.sirenniuniu.message.ResReadyMsg;
import com.idealighter.game.games.sirenniuniu.message.ResReadyOverMsg;
import com.idealighter.game.games.sirenniuniu.message.ResShowdownMsg;
import com.idealighter.game.games.sirenniuniu.struct.SiRenNiuNiuRoom;
import com.idealighter.game.games.sirenniuniu.struct.SiRenNiuNiuSeat;
import com.idealighter.game.games.sirenniuniu.struct.SiRenNiuNiuTable;
import com.idealighter.game.message.core.ResMessage;
import com.idealighter.game.player.manager.PlayerMsgWriter;
import com.idealighter.game.player.struct.Player;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 四人牛牛消息管理.
 * 
 * @date 2016年1月20日 下午4:46:02
 *
 */
@Singleton
public class SiRenNiuNiuMsgMgr {

  @Inject
  private PlayerMsgWriter msgWriter;
  @Inject
  private SiRenNiuNiuDataMgr dataMgr;

  @Inject
  private SirenniuniuRoomTypeDic roomTypeDic;

  /**
   * 发送进入游戏大厅消息.
   */
  public ResMessage sendEnterGameHallMsg() {
    ResEnterGameHallMsg msg = new ResEnterGameHallMsg();

    Collection<SiRenNiuNiuRoom> rooms = dataMgr.newestRooms();
    for (SiRenNiuNiuRoom room : rooms) {
      SirenniuniuRoomDomain roomDom = room.getRoomDomain();
      if (roomDom.getIsActive() != RoomActiveConstant.ACTIVE) {
        continue;
      }
      RoomTypeDetailInfo roomTypeDetailInfo = new RoomTypeDetailInfo();

      roomTypeDetailInfo.setType(roomDom.getType());
      roomTypeDetailInfo.setTypeName(roomTypeDic.map().get(roomDom.getType()).getName());

      RoomInfo roomInfo = toRoomInfo(room);
      roomTypeDetailInfo.getRooms().add(roomInfo);

      msg.getRoomTypes().add(roomTypeDetailInfo);
    }
    return msg;
  }

  /**
   * 房间状态，空闲,普通,拥挤,爆满.
   * 
   * @param room .
   * @return
   */
  private RoomState roomStatus(SiRenNiuNiuRoom room) {
    int playersNum = room.getPlayers().size();
    SirenniuniuRoomDomain roomDom = room.getRoomDomain();

    if (playersNum < roomDom.getMaxNum() * roomDom.getFree() / 100) {
      return RoomState.IDLE;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getGeneral() / 100) {
      return RoomState.GENERAL;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getCrowded() / 100) {
      return RoomState.CROWD;
    } else {
      return RoomState.FULL;
    }
  }

  /**
   * 发送兑换筹码消息.
   * 
   * @param seat 座位信息.
   */
  public void sendChipsChangeMsg(SiRenNiuNiuSeat seat) {
    ResChipsChangeMsg msg = new ResChipsChangeMsg();
    msg.setChips(seat.getTotalChips());
    msg.setOrder(seat.getOrder());
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 发送进入桌子消息.
   * 
   * @param player 玩家.
   */
  public ResMessage sendEnterRoomMsg(Player player) {
    ResEnterRoomMsg msg = new ResEnterRoomMsg();
    for (AbstractTable table : player.curRoom.tables()) {
      msg.getTables().add(table.tableInfo());
    }
    msg.setMembers(player.curRoom.memInfos());
    return msg;
  }

  /**
   * 发送进入桌子消息.
   * 
   * @param player 玩家.
   * @param table .
   */
  public void sendEnterTableMsg(Player player, AbstractTable table, long totalChips) {
    ResEnterTableMsg msg = new ResEnterTableMsg();
    AbstractRoom room = table.room();
    List<MemInfo> mems = new ArrayList<>();
    for (Long playerId : table.players()) {
      mems.add(room.memInfo(playerId));
    }
    msg.setMems(mems);
    msg.setTotalChips(totalChips);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 向同桌的玩家发送该座位的玩家已经准备好.
   * 
   * @param seat 座位信息.
   */
  public void sendReadyMsg(SiRenNiuNiuSeat seat) {
    ResReadyMsg msg = new ResReadyMsg();
    msg.setOrder(seat.getOrder());
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 发牌3.
   * 
   * @param seat 座位信息.
   */
  public void sendDealCardsMsg(SiRenNiuNiuSeat seat) {
    ResDealCardsMsg msg = new ResDealCardsMsg();
    msg.setCardsType(seat.getCardsType().niu);
    for (NiuNiuCard card : seat.getBestCards()) {
      msg.getCards().add(card.ordinal());
    }
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送退出桌子消息.
   * 
   * @param seat 座位信息.
   */
  public void sendExitTableMsg(SiRenNiuNiuSeat seat) {
    ResExitTableMsg msg = new ResExitTableMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  public void sendExitRoom(Player player) {
    ResExitRoomMsg msg = new ResExitRoomMsg();
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送座位叫庄消息.
   * 
   * @param seat 座位信息.
   * @param callType . 0:不叫,非0:叫
   */
  public void sendCallDealerMsg(SiRenNiuNiuSeat seat, int callType) {
    ResCallDealerMsg msg = new ResCallDealerMsg();
    msg.setPlayerId(seat.getPlayerId());
    msg.setOrder(seat.getOrder());
    msg.setCallType(callType);
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 发送下注结果消息.
   * 
   * @param seat 座位信息.
   */
  public void sendBetMsg(SiRenNiuNiuSeat seat) {
    ResBetMsg msg = new ResBetMsg();
    msg.setOrder(seat.getOrder());
    msg.setChips(seat.getBetedchips());
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 发送座位摊牌消息.
   * 
   * @param seat 座位信息.
   */
  public void sendShowdownMsg(SiRenNiuNiuSeat seat) {
    ResShowdownMsg msg = new ResShowdownMsg();
    msg.setOrder(seat.getOrder());
    seat.getBestCards().forEach(card -> msg.getBestCards().add(card.ordinal()));
    msg.setCardsType(seat.getCardsType().niu);
    sendTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 发送其他人进入桌子消息.
   * 
   * @param seat 座位信息.
   */
  public void sendOtherEnterTableMsg(SiRenNiuNiuSeat seat) {
    ResOtherEnterTableMsg msg = new ResOtherEnterTableMsg();
    msg.setMem(seat.getTable().getRoom().memInfo(seat.getPlayerId()));
    for (Long playerId : seat.getTable().players()) {
      if (playerId != seat.getPlayerId()) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 向牌中的玩家发送游戏结束消息.
   * 
   * @param table .
   * @param billInfos .
   */
  public void sendGameOver(SiRenNiuNiuTable table, List<BillInfo> billInfos) {
    ResGameOverMsg msg = new ResGameOverMsg();
    msg.setBillInfos(billInfos);
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 发送最新信息.
   *
   * @Title sendGameLastInfo.
   * @param seat 位置.
   * @return 消息.
   */
  public ResMessage sendGameLastInfo(SiRenNiuNiuSeat seat) {
    ResGameInfoMsg msg = new ResGameInfoMsg();
    AbstractRoom room = seat.getTable().room();
    List<MemInfo> mems = new ArrayList<>();
    for (Long playerId : seat.getTable().players()) {
      mems.add(room.memInfo(playerId));
    }
    msg.setMems(mems);
    msg.setRoom(toRoomInfo(seat.getTable().getRoom()));
    msg.setGameInfo(toGameInfo(seat));
    return msg;
  }

  private GameInfo toGameInfo(SiRenNiuNiuSeat mySeat) {
    SiRenNiuNiuTable table = mySeat.getTable();
    GameInfo result = new GameInfo();
    result.setStage(gameStage(table));

    List<ReadyItem> readyList = new ArrayList<ReadyItem>();
    List<CallDealerItem> callDealerList = new ArrayList<CallDealerItem>();
    Long dealer = 0L;
    List<BetItem> betList = new ArrayList<BetItem>();
    MySelfCard mySelfCard = null;
    List<ShowCardItem> showCardList = new ArrayList<ShowCardItem>();

    List<SiRenNiuNiuSeat> seats = table.getSeats();
    for (SiRenNiuNiuSeat seat : seats) {
      if (seat.getPlayerId() > 0) {
        // 准备情况
        ReadyItem readyItem = new ReadyItem();
        readyItem.setOrder(seat.getOrder());
        readyItem.setReady(seat.readied() ? 1 : 0);
        readyList.add(readyItem);
        // 叫庄情况
        if (seat.getCallDealer() != null) {
          CallDealerItem callDealerItem = new CallDealerItem();
          callDealerItem.setOrder(seat.getOrder());
          callDealerItem.setCall(seat.getCallDealer() ? 1 : 0);
          callDealerList.add(callDealerItem);
        }
        // 庄家列表
        if (seat.isDealer()) {
          dealer = seat.getPlayerId();
        }
        // 下注情况
        BetItem betItem = new BetItem();
        betItem.setOrder(seat.getOrder());
        betItem.setChips(seat.getBetedchips());
        betList.add(betItem);

        if (seat.getPlayerId() == mySeat.getPlayerId()) {
          mySelfCard = new MySelfCard();
          mySelfCard.setOrder(seat.getOrder());
          if (seat.getCardsType() != null) {
            mySelfCard.setCardType(seat.getCardsType().niu);
            List<Integer> bestCards = new ArrayList<Integer>();
            for (NiuNiuCard card : seat.getBestCards()) {
              bestCards.add(card.ordinal());
            }
            mySelfCard.setBestCards(bestCards);
          }
        }

        ShowCardItem showCardItem = new ShowCardItem();
        showCardItem = new ShowCardItem();
        showCardItem.setOrder(seat.getOrder());
        showCardItem.setShow(seat.isShowdown() ? 1 : 0);
        if (seat.getCardsType() != null) {
          showCardItem.setCardType(seat.getCardsType().niu);
          List<Integer> bestCards = new ArrayList<Integer>();
          for (NiuNiuCard card : seat.getBestCards()) {
            bestCards.add(card.ordinal());
          }
          showCardItem.setBestCards(bestCards);
        }
        showCardList.add(showCardItem);
      }
    }
    result.setReadyList(readyList);
    result.setCallDealerList(callDealerList);
    result.setDealer(dealer);
    result.setBetList(betList);
    result.setShowCardList(showCardList);

    result.setMySelfCard(mySelfCard);
    return result;
  }

  /**
   * 游戏阶段.
   * 
   * @Title gameStage.
   * @author houdongsheng
   * @date 2018年3月14日 下午1:58:53
   * @param table 桌子
   * @return int(0:准备阶段，1：下注阶段, 2:叫庄阶段, 3:摊牌阶段)
   */
  private int gameStage(SiRenNiuNiuTable table) {
    if (!table.isReadied()) {
      return TableStage.READY_STAGE;
    } else {
      if (!table.betOver()) {
        return TableStage.BET_STAGE;
      } else { // (叫庄|摊牌)
        if (!table.callDealerOver()) {
          return TableStage.CALL_DEALER;
        } else {
          if (!table.showdown()) {
            return TableStage.SHOW_CARD;
          } else {
            return TableStage.READY_STAGE;
          }
        }
      }
    }
  }

  private static class TableStage {
    public static final int READY_STAGE = 0;
    public static final int BET_STAGE = 1;
    public static final int CALL_DEALER = 2;
    public static final int SHOW_CARD = 3;
  }

  private RoomInfo toRoomInfo(SiRenNiuNiuRoom room) {
    RoomInfo roomInfo = new RoomInfo();
    SirenniuniuRoomDomain roomDom = room.getRoomDomain();
    roomInfo.setRoomId(room.getId().intValue());
    roomInfo.setName(roomDom.getName());
    roomInfo.setType(roomDom.getType());
    roomInfo.setMaxNum(roomDom.getMaxNum());
    roomInfo.setFree(roomDom.getFree());
    roomInfo.setGeneral(roomDom.getGeneral());
    roomInfo.setCrowded(roomDom.getCrowded());
    roomInfo.setLower(roomDom.getLower());
    roomInfo.setUpper(roomDom.getUpper());
    roomInfo.setProportionGold(roomDom.getProportionGold());
    roomInfo.setProportionChips(roomDom.getProportionChips());
    roomInfo.setTabble(roomDom.getTable());
    roomInfo.setBaseBet(roomDom.getBaseBet());
    roomInfo.setBetOptions(roomDom.getBetOptions());
    roomInfo.setAfee(roomDom.getAfee());
    roomInfo.setInType(roomDom.getInType());
    roomInfo.setPlayerNum(room.getPlayers().size());
    roomInfo.setStatus(roomStatus(room).desc);
    roomInfo.setDisplayNames(roomDom.getDisplays());
    roomInfo.setPlaceHolder(roomDom.getPlaceHolder());
    return roomInfo;
  }

  /**
   * 发送全部准备消息.
   * 
   * @param table .
   */
  public void sendReadyOverMsg(SiRenNiuNiuTable table) {
    ResReadyOverMsg msg = new ResReadyOverMsg();
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 发送全部叫庄消息.
   * 
   * @param table .
   */
  public void sendCallDealerOverMsg(SiRenNiuNiuTable table) {
    ResCallDealerOverMsg msg = new ResCallDealerOverMsg();
    SiRenNiuNiuSeat dealer = table.dealer();
    msg.setDealerOrder(dealer.getOrder());
    msg.setDealer(dealer.getPlayerId());
    sendTablePlayersMsg(table, msg);
  }



  /**
   * 向同桌的玩家(包括自己)发送消息.
   * 
   * @param table .
   * @param msg .
   */
  public void sendTablePlayersMsg(SiRenNiuNiuTable table, ResMessage msg) {
    List<? extends AbstractSeat> seats = table.seats();
    for (int i = 0; i < seats.size(); i++) {
      AbstractSeat seat = seats.get(i);
      long playerId = seat.getPlayerId();
      if (playerId > 0) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 向同房间的玩家(包括自己)发送消息.
   * 
   * @param room .
   * @param msg .
   */
  public void sendRoomPlayersMsg(SiRenNiuNiuRoom room, ResMessage msg) {
    room.getPlayers().forEach(p -> msgWriter.writeMsg(p, msg));
  }
}
